﻿//: -lib
module luac ;

version(Windows) {
	pragma(lib, "lua.lib");
}

private {
	version (D_Version2)
	{
		mixin(`
		alias const(char) cchar; /// const char type
		alias invariant(char) ichar; /// invariant char type

		alias char[] mstring; /// mutable string type
		alias const(char)[] cstring; /// const string type
		alias invariant(char)[] istring; /// invariant string type

		alias wchar[] mwstring;
		alias const(wchar)[] cwstring;
		alias invariant(wchar)[] iwstring;

		alias dchar[] mdstring;
		alias const(dchar)[] cdstring;
		alias invariant(dchar)[] idstring;`);
	} else {
		alias char cchar;
		alias char ichar;

		alias char[] mstring;
		alias char[] cstring;
		alias char[] istring;

		alias wchar[] mwstring;
		alias wchar[] cwstring;
		alias wchar[] iwstring;

		alias dchar[] mdstring;
		alias dchar[] cdstring;
		alias dchar[] idstring;
	}
}

extern (C):

alias ptrdiff_t LUA_INTEGER;
alias size_t LUAI_UMEM;
alias ptrdiff_t LUAI_MEM;
alias int LUAI_INT32;
alias double LUA_NUMBER;
alias double LUAI_UACNUMBER;
alias long LUA_INTFRM_T;

const LUAI_MAXCALLS = 20000;
const LUA_IDSIZE = 60;
const LUAI_GCPAUSE = 200;
const LUAI_GCMUL = 200;
const LUA_COMPAT_LSTR = 1;
const LUAI_MAXCSTACK = 8000;
const LUAI_BITSINT = 32;
const LUA_MAXCAPTURES = 32;
const LUAI_MAXCCALLS = 200;
const LUAI_MAXVARS = 200;
const LUAI_MAXUPVALUES = 60;
const LUAL_BUFFERSIZE = 16384;
const LUAI_EXTRASPACE = 0;
const LUAI_MAXNUMBER2STR = 32;

union luai_Cast
{
    double l_d;
    int l_l;
}


const LUA_VERSION = "Lua 5.1";
const LUA_RELEASE = "Lua 5.1.4";
const LUA_VERSION_NUM = 501;
const LUA_COPYRIGHT = "Copyright (C) 1994-2008 Lua.org, PUC-Rio";
const LUA_AUTHORS = "R. Ierusalimschy, L. H. de Figueiredo & W. Celes";


// mark for precompiled code (`<esc>Lua')
const LUA_SIGNATURE = "\033Lua";

// option for multiple returns in `lua_pcall' and `lua_call'
const LUA_MULTRET = -1;


// pseudo-indices
const LUA_REGISTRYINDEX = -10000;
const LUA_ENVIRONINDEX = -10001;
const LUA_GLOBALSINDEX = -10002;

int lua_upvalueindex (int i) { return LUA_GLOBALSINDEX-i; }


// thread status; 0 is OK
const LUA_YIELD = 1;
const LUA_ERRRUN = 2;
const LUA_ERRSYNTAX = 3;
const LUA_ERRMEM = 4;
const LUA_ERRERR = 5;
const LUA_ERRFILE = LUA_ERRERR+1;

// don't specify lua_State in detail
alias void* lua_State;

typedef int  function(lua_State *L)lua_CFunction;


// functions that read/write blocks when loading/dumping Lua chunks
alias char * function(lua_State *L, void *ud, size_t *sz)lua_Reader;
alias int function(lua_State *L, void *p, size_t sz, void *ud)lua_Writer;

// prototype for memory-allocation functions
alias void * function(void *ud, void *ptr, size_t osize, size_t nsize)lua_Alloc;

// basic types
const LUA_TNONE = -1;
const LUA_TNIL = 0;
const LUA_TBOOLEAN = 1;
const LUA_TLIGHTUSERDATA = 2;
const LUA_TNUMBER = 3;
const LUA_TSTRING = 4;
const LUA_TTABLE = 5;
const LUA_TFUNCTION = 6;
const LUA_TUSERDATA = 7;
const LUA_TTHREAD = 8;

const LUA_MINSTACK = 20;

// type of numbers in Lua */
alias double lua_Number;
alias ptrdiff_t lua_Integer;

// state manipulation
lua_State * lua_newstate(lua_Alloc f, void *ud);
void  lua_close(lua_State *L);
lua_State * lua_newthread(lua_State *L);
lua_CFunction  lua_atpanic(lua_State *L, lua_CFunction panicf);


// basic stack manipulation
int  lua_gettop(lua_State *L);
void  lua_settop(lua_State *L, int idx);
void  lua_pushvalue(lua_State *L, int idx);
void  lua_remove(lua_State *L, int idx);
void  lua_insert(lua_State *L, int idx);
void  lua_replace(lua_State *L, int idx);
int  lua_checkstack(lua_State *L, int sz);

void  lua_xmove(lua_State *from, lua_State *to, int n);


// access functions (stack -> C)
int  lua_isnumber(lua_State *L, int idx);
int  lua_isstring(lua_State *L, int idx);
int  lua_iscfunction(lua_State *L, int idx);
int  lua_isuserdata(lua_State *L, int idx);
int  lua_type(lua_State *L, int idx);
ichar * lua_typename(lua_State *L, int tp);
int  lua_equal(lua_State *L, int idx1, int idx2);
int  lua_rawequal(lua_State *L, int idx1, int idx2);
int  lua_lessthan(lua_State *L, int idx1, int idx2);

lua_Number  lua_tonumber(lua_State *L, int idx);
lua_Integer  lua_tointeger(lua_State *L, int idx);
int  lua_toboolean(lua_State *L, int idx);
ichar * lua_tolstring(lua_State *L, int idx, size_t *len);
size_t  lua_objlen(lua_State *L, int idx);
lua_CFunction  lua_tocfunction(lua_State *L, int idx);
void * lua_touserdata(lua_State *L, int idx);
lua_State * lua_tothread(lua_State *L, int idx);
void * lua_topointer(lua_State *L, int idx);


// push functions (C -> stack)
void  lua_pushnil(lua_State *L);
void  lua_pushnumber(lua_State *L, lua_Number n);
void  lua_pushinteger(lua_State *L, lua_Integer n);
void  lua_pushlstring(lua_State *L, cchar *s, size_t l);
void  lua_pushstring(lua_State *L, cchar *s);
ichar * lua_pushvfstring(lua_State *L, cchar *fmt, ...);
ichar * lua_pushfstring(lua_State *L, cchar *fmt,...);
void  lua_pushcclosure(lua_State *L, lua_CFunction fn, int n);
void  lua_pushboolean(lua_State *L, int b);
void  lua_pushlightuserdata(lua_State *L, void *p);
int  lua_pushthread(lua_State *L);

// get functions (Lua -> stack)
void  lua_gettable(lua_State *L, int idx);
void  lua_getfield(lua_State *L, int idx, cchar *k);
void  lua_rawget(lua_State *L, int idx);
void  lua_rawgeti(lua_State *L, int idx, int n);
void  lua_createtable(lua_State *L, int narr, int nrec);
void * lua_newuserdata(lua_State *L, size_t sz);
int  lua_getmetatable(lua_State *L, int objindex);
void  lua_getfenv(lua_State *L, int idx);

// set functions (stack -> Lua)
void  lua_settable(lua_State *L, int idx);
void  lua_setfield(lua_State *L, int idx, cchar *k);
void  lua_rawset(lua_State *L, int idx);
void  lua_rawseti(lua_State *L, int idx, int n);
int  lua_setmetatable(lua_State *L, int objindex);
int  lua_setfenv(lua_State *L, int idx);

// `load' and `call' functions (load and run Lua code)
void  lua_call(lua_State *L, int nargs, int nresults);
int  lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);
int  lua_cpcall(lua_State *L, lua_CFunction func, void *ud);
int  lua_load(lua_State *L, lua_Reader reader, void *dt, cchar *chunkname);
int  lua_dump(lua_State *L, lua_Writer writer, void *data);


// coroutine functions
int  lua_yield(lua_State *L, int nresults);
int  lua_resume(lua_State *L, int narg);
int  lua_status(lua_State *L);

// garbage-collection function and options
const LUA_GCSTOP = 0;
const LUA_GCRESTART = 1;
const LUA_GCCOLLECT = 2;
const LUA_GCCOUNT = 3;
const LUA_GCCOUNTB = 4;
const LUA_GCSTEP = 5;
const LUA_GCSETPAUSE = 6;
const LUA_GCSETSTEPMUL = 7;

int  lua_gc(lua_State *L, int what, int data);


// miscellaneous functions
int  lua_error(lua_State *L);
int  lua_next(lua_State *L, int idx);
void  lua_concat(lua_State *L, int n);
lua_Alloc  lua_getallocf(lua_State *L, void **ud);
void  lua_setallocf(lua_State *L, lua_Alloc f, void *ud);

// some useful macros
void lua_pop(lua_State* L, int n) { lua_settop(L, -(n)-1); }
void lua_newtable(lua_State* L) { lua_createtable(L, 0, 0); }
void lua_register(lua_State* L, char* n, lua_CFunction f) { lua_pushcfunction(L, f); lua_setglobal(L, n); }
void lua_pushcfunction(lua_State* L, lua_CFunction f) { lua_pushcclosure(L, f, 0); }
int lua_strlen(lua_State* L, int i) { return lua_objlen(L, i); }
bool lua_isfunction(lua_State* L, int n) { return lua_type(L, n) == LUA_TFUNCTION; }
bool lua_istable(lua_State* L, int n) { return lua_type(L, n) == LUA_TTABLE; }
bool lua_islightuserdata(lua_State* L, int n) { return lua_type(L, n) == LUA_TLIGHTUSERDATA; }
bool lua_isnil(lua_State* L, int n) { return lua_type(L, n) == LUA_TNIL; }
bool lua_isboolean(lua_State* L, int n) { return lua_type(L, n) == LUA_TBOOLEAN; }
bool lua_isthread(lua_State* L, int n) { return lua_type(L, n) == LUA_TTHREAD; }
bool lua_isnone(lua_State* L, int n) { return lua_type(L, n) == LUA_TNONE; }
bool lua_isnoneornil(lua_State* L, int n) { return lua_type(L, n) <= 0; }
void lua_pushliteral(lua_State* L, char[] s) { lua_pushlstring(L, (s ~ \0).ptr, s.length);  }
void lua_setglobal(lua_State* L, char* s) { lua_setfield(L, LUA_GLOBALSINDEX, s); }
void lua_getglobal(lua_State* L, char* s) { lua_getfield(L, LUA_GLOBALSINDEX, s); }
ichar* lua_tostring(lua_State* L, int i) { return lua_tolstring(L, i, null); }

// compatibility macros and functions
alias luaL_newstate lua_open ;
void lua_getregistry(lua_State* L) { lua_pushvalue(L, LUA_REGISTRYINDEX); }
int lua_getgccount(lua_State* L) { return lua_gc(L, LUA_GCCOUNT, 0); }
alias lua_Reader lua_Chunkreader;
alias lua_Writer lua_Chunkwriter;

// hack
void lua_setlevel (lua_State *from, lua_State *to);


// Debug API

// Event codes
const LUA_HOOKCALL = 0;
const LUA_HOOKRET = 1;
const LUA_HOOKLINE = 2;
const LUA_HOOKCOUNT = 3;
const LUA_HOOKTAILRET = 4;

// Event masks
const LUA_MASKCALL = 1 << LUA_HOOKCALL;
const LUA_MASKRET = 1 << LUA_HOOKRET;
const LUA_MASKLINE = 1 << LUA_HOOKLINE;
const LUA_MASKCOUNT = 1 << LUA_HOOKCOUNT;

alias void  function(lua_State *L, lua_Debug *ar)lua_Hook;

int  lua_getstack(lua_State *L, int level, lua_Debug *ar);
int  lua_getinfo(lua_State *L, cchar *what, lua_Debug *ar);
ichar * lua_getlocal(lua_State *L, lua_Debug *ar, int n);
ichar * lua_setlocal(lua_State *L, lua_Debug *ar, int n);
ichar * lua_getupvalue(lua_State *L, int funcindex, int n);
ichar * lua_setupvalue(lua_State *L, int funcindex, int n);
int  lua_sethook(lua_State *L, lua_Hook func, int mask, int count);
lua_Hook  lua_gethook(lua_State *L);
int  lua_gethookmask(lua_State *L);
int  lua_gethookcount(lua_State *L);

struct lua_Debug
{
    int event;
    char *name;
    char *namewhat;
    char *what;
    char *source;
    int currentline;
    int nups;
    int linedefined;
    int lastlinedefined;
    char [LUA_IDSIZE]short_src;
    int i_ci;
}

/******************************************************************************
* Copyright (C) 1994-2008 Lua.org, PUC-Rio.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
******************************************************************************/


int luaL_getn(lua_State* L, int i) { return lua_objlen(L, i); }
void luaL_setn(lua_State* L, int i, int j) { }

alias luaL_openlib luaI_openlib;

struct luaL_Reg
{
    cchar *name;
    lua_CFunction func;
}

void  luaL_openlib(lua_State *L, cchar *libname, luaL_Reg *l, int nup);
void  luaL_register(lua_State *L, cchar *libname, luaL_Reg *l);
int  luaL_getmetafield(lua_State *L, int obj, cchar *e);
int  luaL_callmeta(lua_State *L, int obj, cchar *e);
int  luaL_typerror(lua_State *L, int narg, cchar *tname);
int  luaL_argerror(lua_State *L, int numarg, cchar *extramsg);
ichar * luaL_checklstring(lua_State *L, int numArg, size_t *l);
ichar * luaL_optlstring(lua_State *L, int numArg, cchar *def, size_t *l);
lua_Number  luaL_checknumber(lua_State *L, int numArg);
lua_Number  luaL_optnumber(lua_State *L, int nArg, lua_Number def);

lua_Integer  luaL_checkinteger(lua_State *L, int numArg);
lua_Integer  luaL_optinteger(lua_State *L, int nArg, lua_Integer def);

void  luaL_checkstack(lua_State *L, int sz, cchar *msg);
void  luaL_checktype(lua_State *L, int narg, int t);
void  luaL_checkany(lua_State *L, int narg);

int  luaL_newmetatable(lua_State *L, cchar *tname);
void * luaL_checkudata(lua_State *L, int ud, cchar *tname);

void  luaL_where(lua_State *L, int lvl);
int  luaL_error(lua_State *L, cchar *fmt,...);

int  luaL_checkoption(lua_State *L, int narg, cchar *def, cchar **lst);

int  luaL_ref(lua_State *L, int t);
void  luaL_unref(lua_State *L, int t, int _ref);

int  luaL_loadfile(lua_State *L, cchar *filename);
int  luaL_loadbuffer(lua_State *L, cchar *buff, size_t sz, cchar *name);
int  luaL_loadstring(lua_State *L, cchar *s);

lua_State * luaL_newstate();

ichar * luaL_gsub(lua_State *L, cchar *s, cchar *p, cchar *r);

ichar * luaL_findtable(lua_State *L, int idx, cchar *fname, int szhint);

// some useful macros

void luaL_argcheck(lua_State* L, int cond, int numarg, cchar* extramsg) { if (!cond) luaL_argerror(L, numarg, extramsg); }
ichar* luaL_checkstring(lua_State* L, int n) { return luaL_checklstring(L, n, null); }
ichar* luaL_optstring(lua_State* L, int n, cchar* d) { return luaL_optlstring(L, n, d, null); }
int luaL_checkint(lua_State* L, int n) { return luaL_checkinteger(L, n); }
int luaL_optint (lua_State* L, int n, int d) { return luaL_optinteger(L, n, d); }
long luaL_checklong(lua_State* L, int n) { return luaL_checkinteger(L, n); }
int luaL_optlong(lua_State* L, int n, int d) { return luaL_optinteger(L, n, d); }

ichar* luaL_typename(lua_State* L, int i) { return lua_typename(L, lua_type(L, i)); }

int luaL_dofile(lua_State* L, cchar* fn) { return luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0); }

int luaL_dostring(lua_State*L, cchar* s) { return luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0); }

void luaL_getmetatable(lua_State* L, cchar* s) { lua_getfield(L, LUA_REGISTRYINDEX, s); }

bool luaL_opt(lua_State* L, int function(lua_State*, int) f, int n, int d) { return luaL_opt(L, f, n, d); }

// Generic Buffer manipulation
struct luaL_Buffer
{
    char *p;
    int lvl;
    lua_State *L;
    char [LUAL_BUFFERSIZE]buffer;
}

void luaL_addchar(luaL_Buffer* B, char c)
{
	if (B.p < B.buffer.ptr + LUAL_BUFFERSIZE || (luaL_prepbuffer(B)))
	{
		*B.p = c;
		B.p++;
	}
}

void luaL_putchar(luaL_Buffer* B, char c) { luaL_addchar(B, c); }

void luaL_addsize(luaL_Buffer* B, int n) { B.p += n; }

void  luaL_buffinit(lua_State *L, luaL_Buffer *B);
char * luaL_prepbuffer(luaL_Buffer *B);
void  luaL_addlstring(luaL_Buffer *B, cchar *s, size_t l);
void  luaL_addstring(luaL_Buffer *B, cchar *s);
void  luaL_addvalue(luaL_Buffer *B);
void  luaL_pushresult(luaL_Buffer *B);


// compatibility with ref system

const LUA_NOREF = -2;
const LUA_REFNIL = -1;

void lua_ref(lua_State* L, int lock) { lock ? luaL_ref(L, LUA_REGISTRYINDEX) : lua_pushstring(L, "unlocked reference are obsolete"); lua_error(L); }
void lua_unref(lua_State* L, int _ref) { luaL_unref(L, LUA_REGISTRYINDEX, _ref); }
void lua_getref(lua_State* L, int _ref) { lua_rawgeti(L, LUA_REGISTRYINDEX, _ref); }


const LUA_FILEHANDLE = "FILE*";
const LUA_COLIBNAME = "coroutine";
int  luaopen_base(lua_State *L);
const LUA_TABLIBNAME = "table";
int  luaopen_table(lua_State *L);
const LUA_IOLIBNAME = "io";
int  luaopen_io(lua_State *L);
const LUA_OSLIBNAME = "os";
int  luaopen_os(lua_State *L);
const LUA_STRLIBNAME = "string";
int  luaopen_string(lua_State *L);
const LUA_MATHLIBNAME = "math";
int  luaopen_math(lua_State *L);
const LUA_DBLIBNAME = "debug";
int  luaopen_debug(lua_State *L);
const LUA_LOADLIBNAME = "package";
int  luaopen_package(lua_State *L);

void  luaL_openlibs(lua_State *L);
